﻿using System.Collections.Generic;
using System.Text;
using System.Web.Routing;

namespace MvcSupplantCaching
{
    /// <summary>
    /// Builds the cache keys for the output cache and supplant cache.
    /// </summary>
    public class KeyBuilder : IKeyBuilder
    {
        /// <summary>
        /// The cache key prefix to prepend to all cache keys.
        /// </summary>
        private string _cacheKeyPrefix = "_supplant.";

        /// <summary>
        /// The cache key prefix to prepend to all cache keys.
        /// </summary>
        public string CacheKeyPrefix
        {
            get
            {
                return _cacheKeyPrefix;
            }
            set
            {
                _cacheKeyPrefix = value;
            }
        }

        /// <summary>
        /// Builds a cache key based on the <paramref name="controllerName"/>.
        /// </summary>
        /// <param name="controllerName">The controller name used to vary the cache key with.</param>
        /// <returns>The cache key.</returns>
        public string BuildKey(string controllerName)
        {
            return BuildKey(controllerName, null, null);
        }

        /// <summary>
        /// Builds a cache key based on the <paramref name="controllerName"/> and <paramref name="actionName"/>.
        /// </summary>
        /// <param name="controllerName">The controller name used to vary the cache key with.</param>
        /// <param name="actionName">The action name used to vary the cache key with.</param>
        /// <returns>The cache key.</returns>
        public string BuildKey(string controllerName, string actionName)
        {
            return BuildKey(controllerName, actionName, null);
        }

        /// <summary>
        /// Builds a cache key based on the <paramref name="controllerName"/> and <paramref name="actionName"/>.
        /// </summary>
        /// <param name="controllerName">The controller name used to vary the cache key with.</param>
        /// <param name="actionName">The action name used to vary the cache key with.</param>
        /// <param name="routeValues">The route value dictionary used to vary the cache key with.</param>
        /// <returns>The cache key.</returns>
        public string BuildKey(string controllerName, string actionName, RouteValueDictionary routeValues)
        {
            var builder = new StringBuilder(CacheKeyPrefix);

            if (controllerName != null)
            {
                builder.AppendFormat("{0}.", controllerName.ToLowerInvariant());
            }

            if (actionName != null)
            {
                builder.AppendFormat("{0}#", actionName.ToLowerInvariant());
            }

            if (routeValues != null)
            {
                foreach (var routeValue in routeValues)
                {
                    builder.Append(BuildKeyFragment(routeValue));
                }
            }

            return builder.ToString();
        }

        /// <summary>
        /// Builds out a key fragment based on the <paramref name="routeValue"/>.
        /// </summary>
        /// <param name="routeValue">The route value dictionary to use for building out the key fragment.</param>
        /// <returns>A cache key fragment varied by the route values.</returns>
        public string BuildKeyFragment(KeyValuePair<string, object> routeValue)
        {
            var value = routeValue.Value == null ? "<null>" : routeValue.Value.ToString().ToLowerInvariant();

            return string.Format("{0}={1}#", routeValue.Key.ToLowerInvariant(), value);
        }
    }
}
